<html>
    <head>
        <title>使用Roslyn动态编译C#脚本</title>
    </head>
    <body>
        <script>
            // Roslyn动态编译C#脚本

                /*
                        在ABP应用程序中使用Roslyn动态编译C#脚本，需要先添加必要的NuGet包，然后创建一个服务类处理编译逻辑。

                        以下是具体步骤和实例代码：
                */

                /*
                    一、安装

                             添加NuGet包

                               首先在你的项目中安装以下NuGet包：

                                        ①、Microsoft.CodeAnalysis.CSharp
                                        
                                        ②、Microsoft.CodeAnalysis.CSharp.Scripting
                */

                /*

                    二、、创建编译服务

                                创建一个服务类来处理代码编译和执行，下面是一个示例：

                                eg:
                                    using System;
                                    using System.Collections.Generic;
                                    using System.IO;
                                    using System.Linq;
                                    using System.Reflection;
                                    using System.Runtime.Loader;
                                    using System.Threading.Tasks;
                                    using Microsoft.CodeAnalysis;
                                    using Microsoft.CodeAnalysis.CSharp;
                                    using Microsoft.CodeAnalysis.Emit;
                                    using Volo.Abp.DependencyInjection;


                                    namespance YourNamespace
                                    {
                                        public class DynamicCompilerService:ITransientDependency
                                        {
                                            private readonly  List<MetadataReference> _references = new List<MetadataReference>();

                                            public DynamicCompilerService()
                                            {
                                                
                                            }

                                            private void AddDefaultReferences()
                                            {
                                                // 添加.net 标准库引用
                                                AddReference(typeof(object).Assembly);
                                                AddReference(typeof(System.Linq.Enumerable).Assembly);
                                                AddReference(typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly);
                                                AddReference(typeof(Volo.Abp.AbpException).Assembly);

                                                // 添加其他可能需要的ABP模块
                                            }


                                            // 对程序集添加引用
                                            public void AddReference(Assembly assembly)
                                            {
                                                _references.Add(MeradataReference.CreateFromFile(assembly.Location));
                                            }


                                            // 动态编译并执行代码
                                            public async Task<object> CompileAndEx3cuteAsync(string code,string entryMethod = "Execute",params object[] parameters)
                                            {
                                                  // 创建语法树
                                                  SyntaxTree syntaxTree =CSharpSyntaxTree.ParseText(code);
                                                   

                                                  // 创建编译选项
                                                  CSharpCompilationOptions options = new CSharpCompilationOptions(
                                                        OutputKind.DynamicallyLinkedLibrary,
                                                        optimizationLevel: OptimizationLevel.Release,  // 设置优化级别
                                                        allowUnsafe:true
                                                  );

                                                  // 创建编译对象
                                                  CsharpCompilation compilation = CSharpCompilation.Create(
                                                        $"DynamicCompilation_{Guid.NewGuid()}",
                                                        new[] {syntaxTreee},
                                                        _references,
                                                        options
                                                  );


                                                  // 在内存中编译
                                                  using( MemoryStream ms = new MemoryStream())
                                                  {
                                                      EmitResult result = compilation.Emit(ms);  // 触发编译

                                                      if(!result.Success)  // 编译失败    diagnostic:诊断      severity:严重程度，严重性         
                                                      {
                                                          IEnumerable<Diagnostic> failurs = result.Diagnostics.Where(diagnostic=>diagnostic.IsWarnAsError || diagnostic.Severity==DiagnosticSeverity.Error);

                                                          string errorMessage = string.Join(Environment.NewLine,failures.Select(f=>f.toString()));
                                                          
                                                          throw new InvalidOperationException($"动态编译错误：{errorMessage}");
                                                      }


                                                      ms.Seek(0,SeekOrgin.Begin);

                                                      // 加载程序集
                                                      Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);


                                                      // 获取程序集中所有类型
                                                      Type[] types = assembly.GetTypes();
                                                      
                                                      // 获取带有名为 "Execute" 方法的类型
                                                      Type entryType = types.FirstOrDefault(t=>t.GetMethod(entryMethod) !=null);

                                                      if(method==null)
                                                      {
                                                            throw new InvaliOperationException($"找不到包含'{entryMethod}'方法的类型")
                                                      }

                                                      MethodInfo method = entryType.GetMethod(entryMethod);

                                                      if(method==null)
                                                      {
                                                            throw new InvalidOperationException($"找不到方法'{entryMethod}'")
                                                      }

                                                      // 创建实例并执行方法
                                                      object instance = Activator.CreateInstance(entryType);
                                                      
                                                      return method.Invoke(instance,parameters);
                                                  }
                                            }
                                        }
                                    }
                */

                /*
                    三、如何使用编译服务类：

                               using System.Threading.Tasks;
                               using Volo.Abp.Application.Services; 

                               namespace YourNamespace
                               {
                                    public class CodeExecutionAppService: ApplicationService
                                    {
                                         private readonly DynamicCompilerService _compilerService;


                                         // 注入动态编译服务
                                         public CodeExecutionAppService(DynamicCompilerService compilerService)
                                         {
                                            _compilerService = compilerService;
                                         }

                                         public async Task<string> ExcuteCodeAsync(string code)
                                         {
                                            try
                                            {
                                                // 添加ABP相关引用
                                                _compilerService.AddReference(typeof(CurrentUser).Assembly);
                                                
                                                _compilerService.AddReference(typeof(Logger).Assembly);

                                                // 执行编译的代码
                                                var result = await _compilerService.CompileAndExecuteAsync(code);
                                                return result?.ToString()?? "执行成功，单没有返回值"；

                                            }
                                            catch(Exception ex)
                                            {
                                                return $"执行失败：{ex.Message}"
                                            }
                                         }
                                    }
                               }
                */

                /*
                    四、示例脚本

                            你可以使用类似下面的代码字符串进行测试：

                            public class DynamicCode
                            {
                                public string Excute()
                                {
                                    return "动态脚本执行成功！当前时间："+DateTime.Now.ToString();
                                }
                            }
                */

                /*
                    五、注意事项：
                    
                            1、安全性： 
                                            
                                    动态编译代码存在安全风险，应仅在可控环境中使用，避免执行不可信的代码

                            2、引用管理：  根据你的代码需求，可能需要添加更多的程序集引用。

                            3、性能考虑： 动态编译会带来一定的性能开销，不适合频繁调用的场景。

                            4、ABP集成：  如果需要再动态代码中使用ABP的服务，可以通过依赖注入传递相关服务实例。
                */
        </script>
    </body>
</html>